#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
基础资料模块 - 包含4个子页面组件

此模块将原来的基础资料页面拆分为4个独立的子页面：
1. 房屋资料子页面
2. 承租人资料子页面
3. 出租人资料子页面
4. 水电费标准子页面
"""

# PyQt5组件导入
from PyQt5.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QGroupBox, QFormLayout, QTableWidget,
    QTableWidgetItem, QHeaderView, QPushButton, QLineEdit, QComboBox, QLabel,
    QMessageBox, QFileDialog, QCheckBox
)
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot, QRunnable, QThread

# 系统模块导入
from logger_module import log_info, log_error, log_debug, log_warning
from db_utils import DatabaseUtils


class HouseDataModule(QWidget):
    """房屋资料子页面模块"""
    
    def __init__(self, parent_page=None):
        super().__init__()
        self.conn = None  # 数据库连接将在loadHouses方法中设置
        self.parent_page = parent_page  # 引用主页面，用于通知其他模块刷新
        self.initUI()
    
    def initUI(self):
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建房屋资料框架
        house_data_group = QGroupBox('房屋资料')
        house_layout = QVBoxLayout(house_data_group)
        
        # 创建房屋资料输入表单
        form_layout = QFormLayout()
        
        # 房屋编号
        self.house_no_edit = QLineEdit()
        form_layout.addRow('房屋编号:', self.house_no_edit)
        
        # 房屋类型（可编辑）
        self.house_type_combo = QComboBox()
        self.house_type_combo.setEditable(True)  # 设置为可编辑状态
        self.house_type_combo.addItems(['全部', '门面', '办公室', '仓库', '招待所', '其它'])
        form_layout.addRow('房屋类型:', self.house_type_combo)
        
        # 房屋位置
        self.house_location_edit = QLineEdit()
        location_label = QLabel('房屋位置:')
        form_layout.addRow(location_label, self.house_location_edit)
        
        # 房屋面积和用途（同一行）
        area_usage_layout = QHBoxLayout()
        self.house_area_edit = QLineEdit()
        area_usage_layout.addWidget(self.house_area_edit)
        area_usage_layout.addSpacing(10)
        
        # 房屋用途选择（添加全部选项用于查询）
        self.house_usage_combo = QComboBox()
        self.house_usage_combo.setEditable(False)  # 设置为不可编辑
        self.house_usage_combo.addItems(['全部', '商用', '住宅'])
        area_usage_layout.addWidget(self.house_usage_combo)
        
        form_layout.addRow('房屋面积(平方米):', area_usage_layout)
        
        # 添加表单到布局
        house_layout.addLayout(form_layout)
        
        # 创建按钮布局
        button_layout = QHBoxLayout()
        
        # 添加按钮
        self.add_button = QPushButton('添加')
        self.add_button.clicked.connect(self.addHouse)
        button_layout.addWidget(self.add_button)
        
        # 编辑按钮
        self.edit_button = QPushButton('编辑')
        self.edit_button.clicked.connect(self.editHouse)
        button_layout.addWidget(self.edit_button)
        
        # 删除按钮
        self.delete_button = QPushButton('删除')
        self.delete_button.clicked.connect(self.deleteHouse)
        button_layout.addWidget(self.delete_button)
        
        # 查询按钮
        self.query_button = QPushButton('查询')
        self.query_button.clicked.connect(self.queryHouses)
        button_layout.addWidget(self.query_button)
        
        # 重置按钮
        self.reset_button = QPushButton('重置')
        self.reset_button.clicked.connect(self.resetForm)
        button_layout.addWidget(self.reset_button)
        
        # 导入Excel按钮
        self.import_excel_button = QPushButton('导入Excel')
        self.import_excel_button.clicked.connect(self.importHouseFromExcel)
        button_layout.addWidget(self.import_excel_button)
        
        # 导出Excel按钮
        self.export_excel_button = QPushButton('导出Excel')
        self.export_excel_button.clicked.connect(self.exportHouseToExcel)
        button_layout.addWidget(self.export_excel_button)
        
        # 添加按钮布局到主布局
        house_layout.addLayout(button_layout)
        
        # 创建房屋资料表格
        self.house_table = QTableWidget()
        self.house_table.setColumnCount(6)
        self.house_table.setHorizontalHeaderLabels(['ID', '房屋编号', '房屋类型', '房屋位置', '房屋面积', '用途'])
        # 设置ID列不可见
        self.house_table.setColumnHidden(0, True)
        # 设置表格列宽自适应
        self.house_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # 为表格添加双击事件
        self.house_table.cellDoubleClicked.connect(self.onTableDoubleClick)
        
        # 添加表格到布局
        house_layout.addWidget(self.house_table)
        
        # 添加框架到主布局
        main_layout.addWidget(house_data_group)
    
    def loadHouses(self, conn):
        # 设置数据库连接
        self.conn = conn
        # 加载所有不同的房屋类型到下拉列表
        self.loadHouseTypes()
        # 加载所有房屋资料
        self.queryHouses()
    
    def loadHouseTypes(self):
        """从数据库中加载所有不同的房屋类型到下拉列表中"""
        if not self.conn:
            return
            
        try:
            # 保存当前选中的房屋类型
            current_house_type = self.house_type_combo.currentText()
            
            # 清空并添加'全部'选项到房屋资料的下拉列表
            self.house_type_combo.clear()
            self.house_type_combo.addItem('全部')
            
            # 从数据库中获取所有不同的房屋类型
            cursor = self.conn.cursor()
            cursor.execute("SELECT DISTINCT house_type FROM houses WHERE house_type IS NOT NULL AND house_type != '' ORDER BY house_type")
            
            # 添加从数据库获取的房屋类型
            for row in cursor.fetchall():
                house_type = row[0]
                if house_type and house_type != '全部':
                    self.house_type_combo.addItem(house_type)
            
            # 尝试恢复之前选中的房屋类型
            index = self.house_type_combo.findText(current_house_type)
            if index != -1:
                self.house_type_combo.setCurrentIndex(index)
        except Exception as e:
            log_error(f"加载房屋类型失败: {str(e)}")
    
    def queryHouses(self):
        """查询房屋资料"""
        if not self.conn:
            return
            
        try:
            # 获取查询条件
            house_no = self.house_no_edit.text().strip()
            house_type = self.house_type_combo.currentText().strip()
            house_location = self.house_location_edit.text().strip()
            house_usage = self.house_usage_combo.currentText().strip()
            
            # 构建查询SQL
            query_sql = "SELECT id, house_no, house_type, house_location, house_area, usage FROM houses WHERE 1=1"
            params = []
            
            if house_no:
                query_sql += " AND house_no LIKE ?"
                params.append(f"%{house_no}%")
            
            if house_type and house_type != '全部':
                query_sql += " AND house_type LIKE ?"
                params.append(f"%{house_type}%")
            
            if house_location:
                query_sql += " AND house_location LIKE ?"
                params.append(f"%{house_location}%")
            
            if house_usage and house_usage != '全部':
                query_sql += " AND usage = ?"
                params.append(house_usage)
            
            query_sql += " ORDER BY house_no"
            
            # 执行查询
            cursor = self.conn.cursor()
            cursor.execute(query_sql, params)
            houses = cursor.fetchall()
            
            # 清空表格
            self.house_table.setRowCount(0)
            
            # 填充表格
            for row_data in houses:
                row_position = self.house_table.rowCount()
                self.house_table.insertRow(row_position)
                
                for col_idx, value in enumerate(row_data):
                    item = QTableWidgetItem(str(value) if value is not None else '')
                    # 所有单元格不可编辑
                    item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                    self.house_table.setItem(row_position, col_idx, item)
                    
                    # 为第4列（房屋面积）设置右对齐
                    if col_idx == 4:
                        item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
        except Exception as e:
            log_error(f"查询房屋资料失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"查询房屋资料失败: {str(e)}")
    
    def addHouse(self):
        """添加房屋资料"""
        # 调用父类的方法实现添加功能
        self._saveHouse(None)
    
    def editHouse(self):
        """编辑房屋资料"""
        # 获取选中的行
        selected_rows = self.house_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "提示", "请先选择一行要编辑的数据")
            return
            
        # 获取选中行的ID
        row = selected_rows[0].row()
        house_id = self.house_table.item(row, 0).text()
        
        # 调用保存方法进行编辑
        self._saveHouse(house_id)
    
    def _saveHouse(self, house_id):
        """保存房屋资料（添加或编辑）"""
        if not self.conn:
            return
            
        try:
            # 获取表单数据
            house_no = self.house_no_edit.text().strip()
            house_type = self.house_type_combo.currentText().strip()
            house_location = self.house_location_edit.text().strip()
            house_area = self.house_area_edit.text().strip()
            house_usage = self.house_usage_combo.currentText().strip()
            
            # 验证必填字段
            if not house_no:
                QMessageBox.warning(self, "提示", "房屋编号不能为空")
                return
                
            if not house_type:
                QMessageBox.warning(self, "提示", "房屋类型不能为空")
                return
                
            if not house_location:
                QMessageBox.warning(self, "提示", "房屋位置不能为空")
                return
                
            # 验证房屋编号唯一性（编辑时排除当前记录）
            cursor = self.conn.cursor()
            if house_id:
                cursor.execute("SELECT id FROM houses WHERE house_no = ? AND id != ?", (house_no, house_id))
            else:
                cursor.execute("SELECT id FROM houses WHERE house_no = ?", (house_no,))
                
            if cursor.fetchone():
                QMessageBox.warning(self, "提示", "房屋编号已存在，请使用其他编号")
                return
            
            # 保存数据
            if house_id:
                # 编辑现有记录
                cursor.execute(
                    "UPDATE houses SET house_no=?, house_type=?, house_location=?, house_area=?, usage=? WHERE id=?",
                    (house_no, house_type, house_location, house_area if house_area else None, 
                     house_usage if house_usage != '全部' else '商用', house_id)
                )
                log_info(f"编辑房屋资料: ID={house_id}")
                QMessageBox.information(self, "成功", "房屋资料编辑成功")
            else:
                # 添加新记录
                cursor.execute(
                    "INSERT INTO houses (house_no, house_type, house_location, house_area, usage) VALUES (?, ?, ?, ?, ?)",
                    (house_no, house_type, house_location, house_area if house_area else None, 
                     house_usage if house_usage != '全部' else '商用')
                )
                log_info(f"添加房屋资料: 编号={house_no}")
                QMessageBox.information(self, "成功", "房屋资料添加成功")
                
            # 提交事务
            self.conn.commit()
            
            # 重置表单
            self.resetForm()
            
            # 重新加载数据
            self.queryHouses()
            
            # 更新相关的下拉列表
            self.loadHouseTypes()
            
            # 通知主页面刷新水电费标准模块的房屋类型数据
            if self.parent_page and hasattr(self.parent_page, 'utility_fee_module'):
                self.parent_page.utility_fee_module.loadHouseTypes()
        except Exception as e:
            log_error(f"保存房屋资料失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"保存房屋资料失败: {str(e)}")
            if self.conn:
                self.conn.rollback()
    
    def deleteHouse(self):
        """删除房屋资料"""
        if not self.conn:
            return
            
        # 获取选中的行
        selected_rows = self.house_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "提示", "请先选择要删除的数据")
            return
            
        # 确认删除
        reply = QMessageBox.question(self, "确认删除", "确定要删除选中的房屋资料吗？", 
                                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply != QMessageBox.Yes:
            return
            
        try:
            # 开始事务
            cursor = self.conn.cursor()
            
            # 检查是否有合同关联到此房屋
            deleted_count = 0
            for row in selected_rows:
                house_id = self.house_table.item(row.row(), 0).text()
                
                # 检查是否有关联的合同
                cursor.execute("SELECT COUNT(*) FROM contracts WHERE house_no IN (SELECT house_no FROM houses WHERE id=?)", (house_id,))
                if cursor.fetchone()[0] > 0:
                    QMessageBox.warning(self, "提示", "该房屋已关联合同，无法删除")
                    continue
                
                # 删除记录
                cursor.execute("DELETE FROM houses WHERE id=?", (house_id,))
                deleted_count += 1
            
            # 提交事务
            self.conn.commit()
            
            if deleted_count > 0:
                log_info(f"删除房屋资料: 共删除{deleted_count}条记录")
                QMessageBox.information(self, "成功", f"成功删除{deleted_count}条房屋资料")
                # 重新加载数据
                self.queryHouses()
        except Exception as e:
            log_error(f"删除房屋资料失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"删除房屋资料失败: {str(e)}")
            if self.conn:
                self.conn.rollback()
    
    def resetForm(self):
        """重置表单，清除数据并重新加载"""
        # 清除表单数据
        self.house_no_edit.clear()
        self.house_type_combo.setCurrentIndex(0)  # 重置为'全部'
        self.house_location_edit.clear()
        self.house_area_edit.clear()
        self.house_usage_combo.setCurrentIndex(0)  # 重置为'全部'
        
        # 重新加载数据，恢复到初始状态
        self.queryHouses()
    
    def onTableDoubleClick(self, row, column):
        """处理表格双击事件，用于编辑数据"""
        # 将选中行的数据填充到表单中
        house_id = self.house_table.item(row, 0).text()
        self.house_no_edit.setText(self.house_table.item(row, 1).text())
        
        # 设置房屋类型
        house_type = self.house_table.item(row, 2).text()
        index = self.house_type_combo.findText(house_type)
        if index != -1:
            self.house_type_combo.setCurrentIndex(index)
        else:
            self.house_type_combo.setCurrentText(house_type)
            
        self.house_location_edit.setText(self.house_table.item(row, 3).text())
        
        # 设置房屋面积（可能为空）
        area_item = self.house_table.item(row, 4)
        if area_item:
            self.house_area_edit.setText(area_item.text())
        else:
            self.house_area_edit.clear()
            
        # 设置房屋用途
        usage_item = self.house_table.item(row, 5)
        if usage_item:
            usage = usage_item.text()
            index = self.house_usage_combo.findText(usage)
            if index != -1:
                self.house_usage_combo.setCurrentIndex(index)
    
    def importHouseFromExcel(self):
        """从Excel导入房屋资料"""
        # 检查是否有数据库连接
        if not self.conn:
            QMessageBox.critical(self, "错误", "数据库连接未初始化，请重新登录系统")
            return
            
        # 选择Excel文件
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择Excel文件", "", "Excel Files (*.xlsx *.xls);;All Files (*)"
        )
        
        if not file_path:
            return
        
        # 验证文件格式
        import os
        file_ext = os.path.splitext(file_path)[1].lower()
        if file_ext not in ['.xlsx', '.xls']:
            QMessageBox.warning(self, "警告", "仅支持.xlsx和.xls格式的Excel文件")
            return
        
        # 验证文件大小（不超过5MB）
        file_size = os.path.getsize(file_path)
        if file_size > 5 * 1024 * 1024:  # 5MB
            QMessageBox.warning(self, "警告", "文件大小不能超过5MB")
            return
        
        # 创建导入进度对话框
        progress_dialog = QMessageBox(self)
        progress_dialog.setWindowTitle("导入进度")
        progress_dialog.setIcon(QMessageBox.Information)
        progress_dialog.setText("正在解析Excel文件...")
        progress_dialog.setStandardButtons(QMessageBox.Cancel)
        progress_dialog.show()
        
        # 强制进度对话框显示
        progress_dialog.repaint()
        
        # 创建一个标志来跟踪是否取消导入
        import threading
        cancel_flag = threading.Event()
        
        def on_cancel():
            cancel_flag.set()
            progress_dialog.setStandardButtons(QMessageBox.NoButton)
            progress_dialog.setText("正在取消导入...")
        
        progress_dialog.button(QMessageBox.Cancel).clicked.connect(on_cancel)
        
        try:
            # 导入pandas和相关库用于解析Excel
            import pandas as pd
            
            # 解析Excel文件
            df = pd.read_excel(file_path)
            
            if cancel_flag.is_set():
                progress_dialog.close()
                QMessageBox.information(self, "提示", "已取消导入")
                return
            
            # 验证Excel文件格式（检查必需的列）
            required_columns = ['房屋编号', '房屋类型', '房屋位置']
            missing_columns = [col for col in required_columns if col not in df.columns]
            
            if missing_columns:
                progress_dialog.close()
                QMessageBox.warning(self, "格式错误", f"Excel文件缺少必需的列: {', '.join(missing_columns)}")
                
                # 提示用户正确的格式
                format_info = """
请确保Excel文件包含以下列：
- 房屋编号（必需）
- 房屋类型（必需）
- 房屋位置（必需）
- 房屋面积（可选）
- 用途（可选）
                """
                QMessageBox.information(self, "Excel格式说明", format_info)
                return
            
            # 准备导入数据
            total_rows = len(df)
            if total_rows == 0:
                progress_dialog.close()
                QMessageBox.information(self, "提示", "Excel文件中没有数据")
                return
            
            # 更新进度对话框
            progress_dialog.setText(f"准备导入 {total_rows} 条房屋记录...")
            progress_dialog.repaint()
            
            # 初始化导入统计
            success_count = 0
            fail_count = 0
            fail_records = []
            
            # 开始导入数据
            for index, row in df.iterrows():
                if cancel_flag.is_set():
                    break
                
                # 更新进度
                progress_dialog.setText(f"正在导入第 {index + 1}/{total_rows} 条记录...")
                progress_dialog.repaint()
                
                try:
                    # 获取数据（处理缺失值）
                    house_no = str(row['房屋编号']).strip() if pd.notna(row['房屋编号']) else ''
                    house_type = str(row['房屋类型']).strip() if pd.notna(row['房屋类型']) else ''
                    house_location = str(row['房屋位置']).strip() if pd.notna(row['房屋位置']) else ''
                    house_area = str(row.get('房屋面积', '')).strip() if pd.notna(row.get('房屋面积')) else ''
                    usage = str(row.get('用途', '')).strip() if pd.notna(row.get('用途')) else ''
                    
                    # 数据验证
                    if not house_no or not house_type or not house_location:
                        fail_count += 1
                        fail_records.append((index + 2, "数据不完整：房屋编号、房屋类型和房屋位置为必填项"))
                        continue
                    
                    # 检查房屋编号是否已存在
                    cursor = self.conn.cursor()
                    cursor.execute("SELECT id FROM houses WHERE house_no = ?", (house_no,))
                    if cursor.fetchone():
                        # 更新现有记录
                        update_sql = """
                        UPDATE houses 
                        SET house_type = ?, house_location = ?, house_area = ?, usage = ? 
                        WHERE house_no = ?
                        """
                        cursor.execute(update_sql, (house_type, house_location, house_area, usage, house_no))
                    else:
                        # 插入新记录
                        insert_sql = """
                        INSERT INTO houses (house_no, house_type, house_location, house_area, usage) 
                        VALUES (?, ?, ?, ?, ?)
                        """
                        cursor.execute(insert_sql, (house_no, house_type, house_location, house_area, usage))
                    
                    success_count += 1
                    
                except Exception as e:
                    fail_count += 1
                    fail_records.append((index + 2, f"导入失败：{str(e)}"))
            
            # 提交事务
            if not cancel_flag.is_set():
                self.conn.commit()
            
            # 关闭进度对话框
            progress_dialog.close()
            
            if cancel_flag.is_set():
                QMessageBox.information(self, "提示", "已取消导入")
                return
            
            # 显示导入结果
            result_info = f"导入完成！\n成功导入：{success_count} 条记录\n导入失败：{fail_count} 条记录"
            
            if fail_count > 0:
                # 准备错误数据下载
                error_df = pd.DataFrame(fail_records, columns=['行号', '失败原因'])
                
                # 询问用户是否下载错误数据
                reply = QMessageBox.question(
                    self, "导入结果", 
                    f"{result_info}\n\n是否下载错误数据？",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No
                )
                
                if reply == QMessageBox.Yes:
                    # 保存错误数据到Excel
                    error_file_path, _ = QFileDialog.getSaveFileName(
                        self, "保存错误数据", "", "Excel Files (*.xlsx);;All Files (*)"
                    )
                    
                    if error_file_path:
                        try:
                            with pd.ExcelWriter(error_file_path, engine='openpyxl') as writer:
                                error_df.to_excel(writer, index=False, sheet_name='错误记录')
                                
                                # 设置列宽自适应
                                for column in worksheet.columns:
                                    max_length = 0
                                    column_letter = column[0].column_letter
                                    for cell in column:
                                        try:
                                            if len(str(cell.value)) > max_length:
                                                max_length = len(str(cell.value))
                                        except:
                                            pass
                                    adjusted_width = min(max_length + 2, 50)
                                    worksheet.column_dimensions[column_letter].width = adjusted_width
                            
                            QMessageBox.information(self, "成功", f"错误数据已保存到：{error_file_path}")
                        except Exception as e:
                            log_error(f"保存错误数据失败: {str(e)}")
                            QMessageBox.warning(self, "警告", f"保存错误数据失败：{str(e)}")
            else:
                QMessageBox.information(self, "成功", result_info)
            
            # 刷新房屋列表
            self.queryHouses()
            
        except pd.errors.EmptyDataError:
            progress_dialog.close()
            QMessageBox.warning(self, "错误", "Excel文件为空或格式不正确")
        except pd.errors.ParserError:
            progress_dialog.close()
            QMessageBox.warning(self, "错误", "无法解析Excel文件，请检查文件格式")
        except ImportError:
            progress_dialog.close()
            QMessageBox.critical(self, "错误", "缺少必要的库，请安装pandas和openpyxl库")
        except PermissionError:
            progress_dialog.close()
            QMessageBox.warning(self, "错误", "无法访问文件，请检查文件权限或关闭占用该文件的应用程序")
        except Exception as e:
            progress_dialog.close()
            log_error(f"导入Excel文件时发生错误: {str(e)}")
            QMessageBox.critical(self, "错误", f"导入过程中发生错误：{str(e)}")
    
    def exportHouseToExcel(self):
        """导出房屋资料到Excel"""
        # 调用优化的Excel导出方法
        headers = ['房屋编号', '房屋类型', '房屋位置', '房屋面积', '用途']
        
        # 从表格获取数据
        data = []
        for row in range(self.house_table.rowCount()):
            row_data = []
            # 跳过ID列，从第1列开始获取数据
            for col in range(1, self.house_table.columnCount()):
                item = self.house_table.item(row, col)
                row_data.append(item.text() if item else '')
            data.append(row_data)
        
        # 选择保存文件路径
        file_path, _ = QFileDialog.getSaveFileName(
            self, "导出Excel", "", "Excel Files (*.xlsx);;All Files (*)"
        )
        
        if file_path:
            if self.optimizedExportToExcel(headers, data, file_path, "房屋资料"):
                QMessageBox.information(self, "成功", f"房屋资料已成功导出到\n{file_path}")
            else:
                QMessageBox.critical(self, "错误", "导出房屋资料失败")
    
    def optimizedExportToExcel(self, headers, data, file_path, sheet_name):
        """优化的Excel导出方法"""
        try:
            log_info(f"开始导出Excel文件: {file_path}, 工作表: {sheet_name}")
            
            # 导入必要的库
            import pandas as pd
            from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
            from openpyxl.utils import get_column_letter
            
            # 创建DataFrame
            df = pd.DataFrame(data, columns=headers)
            
            # 创建ExcelWriter对象并写入文件
            with pd.ExcelWriter(file_path, engine='openpyxl') as writer:
                df.to_excel(writer, index=False, sheet_name=sheet_name)
                
                # 获取工作表
                worksheet = writer.sheets[sheet_name]
                
                # 设置边框样式
                thin_border = Border(
                    left=Side(style='thin'),
                    right=Side(style='thin'),
                    top=Side(style='thin'),
                    bottom=Side(style='thin')
                )
                
                # 设置表头样式
                header_font = Font(bold=True, color="FFFFFF")
                header_fill = PatternFill(start_color="4F81BD", end_color="4F81BD", fill_type="solid")
                header_alignment = Alignment(horizontal="center", vertical="center")
                
                # 设置数据单元格样式
                data_alignment = Alignment(horizontal="center", vertical="center")
                
                # 应用样式并计算列宽
                column_widths = {}
                
                # 处理表头
                for col_idx, header in enumerate(headers, 1):
                    cell = worksheet.cell(row=1, column=col_idx)
                    cell.font = header_font
                    cell.fill = header_fill
                    cell.alignment = header_alignment
                    cell.border = thin_border
                    
                    # 计算表头列宽
                    column_widths[col_idx] = len(str(header)) + 2
                
                # 处理数据行
                for row_idx, row_data in enumerate(data, 2):
                    for col_idx, cell_value in enumerate(row_data, 1):
                        cell = worksheet.cell(row=row_idx, column=col_idx)
                        cell.alignment = data_alignment
                        cell.border = thin_border
                        
                        # 更新列宽
                        value_length = len(str(cell_value)) + 2
                        if value_length > column_widths.get(col_idx, 0):
                            column_widths[col_idx] = value_length
                
                # 设置自适应列宽
                for col_idx, width in column_widths.items():
                    worksheet.column_dimensions[get_column_letter(col_idx)].width = min(width, 50)
            
            log_info(f"Excel文件导出成功: {file_path}")
            return True
        except Exception as e:
            log_error(f"导出Excel文件时发生错误: {str(e)}")
            return False


class TenantDataModule(QWidget):
    """承租人资料子页面模块"""
    
    def __init__(self):
        super().__init__()
        self.conn = None  # 数据库连接将在loadTenants方法中设置
        self.initUI()
    
    def initUI(self):
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建承租人资料框架
        tenant_data_group = QGroupBox('承租人资料')
        tenant_layout = QVBoxLayout(tenant_data_group)
        
        # 创建承租人资料输入表单
        tenant_form_layout = QFormLayout()
        
        # 承租人名称
        self.tenant_name_edit = QLineEdit()
        tenant_form_layout.addRow('承租人名称:', self.tenant_name_edit)
        
        # 联系人姓名
        self.contact_person_edit = QLineEdit()
        tenant_form_layout.addRow('联系人姓名:', self.contact_person_edit)
        
        # 联系人身份证
        self.contact_id_edit = QLineEdit()
        tenant_form_layout.addRow('联系人身份证:', self.contact_id_edit)
        
        # 联系人电话
        self.contact_phone_edit = QLineEdit()
        tenant_form_layout.addRow('联系人电话:', self.contact_phone_edit)
        
        # 添加表单到布局
        tenant_layout.addLayout(tenant_form_layout)
        
        # 创建按钮布局
        tenant_button_layout = QHBoxLayout()
        
        # 添加按钮
        self.add_tenant_button = QPushButton('添加')
        self.add_tenant_button.clicked.connect(self.addTenant)
        tenant_button_layout.addWidget(self.add_tenant_button)
        
        # 编辑按钮
        self.edit_tenant_button = QPushButton('编辑')
        self.edit_tenant_button.clicked.connect(self.editTenant)
        tenant_button_layout.addWidget(self.edit_tenant_button)
        
        # 删除按钮
        self.delete_tenant_button = QPushButton('删除')
        self.delete_tenant_button.clicked.connect(self.deleteTenant)
        tenant_button_layout.addWidget(self.delete_tenant_button)
        
        # 查询按钮
        self.query_tenant_button = QPushButton('查询')
        self.query_tenant_button.clicked.connect(self.queryTenants)
        tenant_button_layout.addWidget(self.query_tenant_button)
        
        # 重置按钮
        self.reset_tenant_button = QPushButton('重置')
        self.reset_tenant_button.clicked.connect(self.resetTenantForm)
        tenant_button_layout.addWidget(self.reset_tenant_button)
        
        # 导入Excel按钮
        self.import_tenant_excel_button = QPushButton('导入Excel')
        self.import_tenant_excel_button.clicked.connect(self.importTenantFromExcel)
        tenant_button_layout.addWidget(self.import_tenant_excel_button)
        
        # 导出Excel按钮
        self.export_tenant_excel_button = QPushButton('导出Excel')
        self.export_tenant_excel_button.clicked.connect(self.exportTenantToExcel)
        tenant_button_layout.addWidget(self.export_tenant_excel_button)

        # 添加按钮布局到主布局
        tenant_layout.addLayout(tenant_button_layout)
        
        # 创建承租人资料表格
        self.tenant_table = QTableWidget()
        self.tenant_table.setColumnCount(5)
        self.tenant_table.setHorizontalHeaderLabels(['ID', '承租人名称', '联系人姓名', '联系人身份证', '联系人电话'])
        # 设置ID列不可见
        self.tenant_table.setColumnHidden(0, True)
        # 设置表格列宽自适应
        self.tenant_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # 为表格添加双击事件
        self.tenant_table.cellDoubleClicked.connect(self.onTenantTableDoubleClick)
        
        # 添加表格到布局
        tenant_layout.addWidget(self.tenant_table)
        
        # 添加框架到主布局
        main_layout.addWidget(tenant_data_group)
    
    def loadTenants(self, conn):
        # 设置数据库连接
        self.conn = conn
        # 加载所有承租人资料
        self.queryTenants()
    
    def queryTenants(self):
        """查询承租人资料"""
        if not self.conn:
            return
            
        try:
            # 获取查询条件
            tenant_name = self.tenant_name_edit.text().strip()
            contact_person = self.contact_person_edit.text().strip()
            contact_id = self.contact_id_edit.text().strip()
            contact_phone = self.contact_phone_edit.text().strip()
            
            # 构建查询SQL
            query_sql = "SELECT id, tenant_name, contact_person, contact_id, contact_phone FROM tenants WHERE 1=1"
            params = []
            
            if tenant_name:
                query_sql += " AND tenant_name LIKE ?"
                params.append(f"%{tenant_name}%")
            
            if contact_person:
                query_sql += " AND contact_person LIKE ?"
                params.append(f"%{contact_person}%")
            
            if contact_id:
                query_sql += " AND contact_id LIKE ?"
                params.append(f"%{contact_id}%")
            
            if contact_phone:
                query_sql += " AND contact_phone LIKE ?"
                params.append(f"%{contact_phone}%")
            
            query_sql += " ORDER BY tenant_name"
            
            # 执行查询
            cursor = self.conn.cursor()
            cursor.execute(query_sql, params)
            tenants = cursor.fetchall()
            
            # 清空表格
            self.tenant_table.setRowCount(0)
            
            # 填充表格
            for row_data in tenants:
                row_position = self.tenant_table.rowCount()
                self.tenant_table.insertRow(row_position)
                
                for col_idx, value in enumerate(row_data):
                    item = QTableWidgetItem(str(value) if value is not None else '')
                    # 所有单元格不可编辑
                    item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                    self.tenant_table.setItem(row_position, col_idx, item)
        except Exception as e:
            log_error(f"查询承租人资料失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"查询承租人资料失败: {str(e)}")
    
    def addTenant(self):
        """添加承租人资料"""
        self._saveTenant(None)
    
    def editTenant(self):
        """编辑承租人资料"""
        # 获取选中的行
        selected_rows = self.tenant_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "提示", "请先选择一行要编辑的数据")
            return
            
        # 获取选中行的ID
        row = selected_rows[0].row()
        tenant_id = self.tenant_table.item(row, 0).text()
        
        # 调用保存方法进行编辑
        self._saveTenant(tenant_id)
    
    def _saveTenant(self, tenant_id):
        """保存承租人资料（添加或编辑）"""
        if not self.conn:
            return
            
        try:
            # 获取表单数据
            tenant_name = self.tenant_name_edit.text().strip()
            contact_person = self.contact_person_edit.text().strip()
            contact_id = self.contact_id_edit.text().strip()
            contact_phone = self.contact_phone_edit.text().strip()
            
            # 验证必填字段
            if not tenant_name:
                QMessageBox.warning(self, "提示", "承租人名称不能为空")
                return
            
            # 验证承租人名称唯一性（编辑时排除当前记录）
            cursor = self.conn.cursor()
            if tenant_id:
                cursor.execute("SELECT id FROM tenants WHERE tenant_name = ? AND id != ?", (tenant_name, tenant_id))
            else:
                cursor.execute("SELECT id FROM tenants WHERE tenant_name = ?", (tenant_name,))
                
            if cursor.fetchone():
                QMessageBox.warning(self, "提示", "承租人名称已存在，请使用其他名称")
                return
            
            # 保存数据
            if tenant_id:
                # 编辑现有记录
                cursor.execute(
                    "UPDATE tenants SET tenant_name=?, contact_person=?, contact_id=?, contact_phone=? WHERE id=?",
                    (tenant_name, contact_person, contact_id, contact_phone, tenant_id)
                )
                log_info(f"编辑承租人资料: ID={tenant_id}")
                QMessageBox.information(self, "成功", "承租人资料编辑成功")
            else:
                # 添加新记录
                cursor.execute(
                    "INSERT INTO tenants (tenant_name, contact_person, contact_id, contact_phone) VALUES (?, ?, ?, ?)",
                    (tenant_name, contact_person, contact_id, contact_phone)
                )
                log_info(f"添加承租人资料: 名称={tenant_name}")
                QMessageBox.information(self, "成功", "承租人资料添加成功")
                
            # 提交事务
            self.conn.commit()
            
            # 重置表单
            self.resetTenantForm()
            
            # 重新加载数据
            self.queryTenants()
        except Exception as e:
            log_error(f"保存承租人资料失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"保存承租人资料失败: {str(e)}")
            if self.conn:
                self.conn.rollback()
    
    def deleteTenant(self):
        """删除承租人资料"""
        if not self.conn:
            return
            
        # 获取选中的行
        selected_rows = self.tenant_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "提示", "请先选择要删除的数据")
            return
            
        # 确认删除
        reply = QMessageBox.question(self, "确认删除", "确定要删除选中的承租人资料吗？", 
                                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply != QMessageBox.Yes:
            return
            
        try:
            # 开始事务
            cursor = self.conn.cursor()
            
            # 检查是否有合同关联到此承租人
            deleted_count = 0
            for row in selected_rows:
                tenant_id = self.tenant_table.item(row.row(), 0).text()
                
                # 检查是否有关联的合同
                cursor.execute("SELECT COUNT(*) FROM contracts WHERE tenant_id = ?", (tenant_id,))
                if cursor.fetchone()[0] > 0:
                    QMessageBox.warning(self, "提示", "该承租人已关联合同，无法删除")
                    continue
                
                # 删除记录
                cursor.execute("DELETE FROM tenants WHERE id=?", (tenant_id,))
                deleted_count += 1
            
            # 提交事务
            self.conn.commit()
            
            if deleted_count > 0:
                log_info(f"删除承租人资料: 共删除{deleted_count}条记录")
                QMessageBox.information(self, "成功", f"成功删除{deleted_count}条承租人资料")
                # 重新加载数据
                self.queryTenants()
        except Exception as e:
            log_error(f"删除承租人资料失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"删除承租人资料失败: {str(e)}")
            if self.conn:
                self.conn.rollback()
    
    def resetTenantForm(self):
        """重置承租人表单，清除数据并重新加载"""
        # 清除表单数据
        self.tenant_name_edit.clear()
        self.contact_person_edit.clear()
        self.contact_id_edit.clear()
        self.contact_phone_edit.clear()
        
        # 重新加载数据，恢复到初始状态
        self.queryTenants()
    
    def onTenantTableDoubleClick(self, row, column):
        """处理表格双击事件，用于编辑数据"""
        # 将选中行的数据填充到表单中
        tenant_id = self.tenant_table.item(row, 0).text()
        self.tenant_name_edit.setText(self.tenant_table.item(row, 1).text())
        self.contact_person_edit.setText(self.tenant_table.item(row, 2).text())
        self.contact_id_edit.setText(self.tenant_table.item(row, 3).text())
        self.contact_phone_edit.setText(self.tenant_table.item(row, 4).text())
    
    def importTenantFromExcel(self):
        """从Excel导入承租人资料"""
        # 检查是否有数据库连接
        if not self.conn:
            QMessageBox.critical(self, "错误", "数据库连接未初始化，请重新登录系统")
            return
            
        # 选择Excel文件
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择Excel文件", "", "Excel Files (*.xlsx *.xls);;All Files (*)"
        )
        
        if not file_path:
            return
        
        # 验证文件格式
        import os
        file_ext = os.path.splitext(file_path)[1].lower()
        if file_ext not in ['.xlsx', '.xls']:
            QMessageBox.warning(self, "警告", "仅支持.xlsx和.xls格式的Excel文件")
            return
        
        # 验证文件大小（不超过5MB）
        file_size = os.path.getsize(file_path)
        if file_size > 5 * 1024 * 1024:  # 5MB
            QMessageBox.warning(self, "警告", "文件大小不能超过5MB")
            return
        
        # 创建导入进度对话框
        progress_dialog = QMessageBox(self)
        progress_dialog.setWindowTitle("导入进度")
        progress_dialog.setIcon(QMessageBox.Information)
        progress_dialog.setText("正在解析Excel文件...")
        progress_dialog.setStandardButtons(QMessageBox.Cancel)
        progress_dialog.show()
        
        # 强制进度对话框显示
        progress_dialog.repaint()
        
        # 创建一个标志来跟踪是否取消导入
        import threading
        cancel_flag = threading.Event()
        
        def on_cancel():
            cancel_flag.set()
            progress_dialog.setStandardButtons(QMessageBox.NoButton)
            progress_dialog.setText("正在取消导入...")
        
        progress_dialog.button(QMessageBox.Cancel).clicked.connect(on_cancel)
        
        # 记录导入开始时间，用于导入历史
        import datetime
        import_history = {
            'start_time': datetime.datetime.now(),
            'file_name': os.path.basename(file_path),
            'status': '进行中'
        }
        
        try:
            # 导入pandas和相关库用于解析Excel
            import pandas as pd
            
            # 解析Excel文件
            df = pd.read_excel(file_path)
            
            if cancel_flag.is_set():
                progress_dialog.close()
                QMessageBox.information(self, "提示", "已取消导入")
                return
            
            # 验证Excel文件格式（检查必需的列）
            required_columns = ['承租人名称']
            missing_columns = [col for col in required_columns if col not in df.columns]
            
            if missing_columns:
                progress_dialog.close()
                QMessageBox.warning(self, "格式错误", f"Excel文件缺少必需的列: {', '.join(missing_columns)}")
                
                # 提示用户正确的格式
                format_info = """
请确保Excel文件包含以下列：
- 承租人名称（必需）
- 联系人姓名（可选）
- 联系人身份证（可选）
- 联系人电话（可选）
                """
                QMessageBox.information(self, "Excel格式说明", format_info)
                return
            
            # 准备导入数据
            total_rows = len(df)
            if total_rows == 0:
                progress_dialog.close()
                QMessageBox.information(self, "提示", "Excel文件中没有数据")
                return
            
            # 更新进度对话框
            progress_dialog.setText(f"准备导入 {total_rows} 条承租人记录...")
            progress_dialog.repaint()
            
            # 初始化导入统计
            success_count = 0
            fail_count = 0
            fail_records = []
            
            # 开始导入数据
            for index, row in df.iterrows():
                if cancel_flag.is_set():
                    break
                
                # 更新进度
                progress_dialog.setText(f"正在导入第 {index + 1}/{total_rows} 条记录...")
                progress_dialog.repaint()
                
                try:
                    # 获取数据（处理缺失值）
                    tenant_name = str(row['承租人名称']).strip() if pd.notna(row['承租人名称']) else ''
                    contact_person = str(row.get('联系人姓名', '')).strip() if pd.notna(row.get('联系人姓名')) else ''
                    contact_id = str(row.get('联系人身份证', '')).strip() if pd.notna(row.get('联系人身份证')) else ''
                    contact_phone = str(row.get('联系人电话', '')).strip() if pd.notna(row.get('联系人电话')) else ''
                    
                    # 数据验证
                    if not tenant_name:
                        fail_count += 1
                        fail_records.append((index + 2, "数据不完整：承租人名称为必填项"))
                        continue
                    
                    # 检查承租人名称是否已存在
                    cursor = self.conn.cursor()
                    cursor.execute("SELECT id FROM tenants WHERE tenant_name = ?", (tenant_name,))
                    existing_tenant = cursor.fetchone()
                    
                    if existing_tenant:
                        # 更新现有记录
                        update_sql = """
                        UPDATE tenants 
                        SET contact_person = ?, contact_id = ?, contact_phone = ? 
                        WHERE tenant_name = ?
                        """
                        cursor.execute(update_sql, (contact_person, contact_id, contact_phone, tenant_name))
                    else:
                        # 插入新记录
                        insert_sql = """
                        INSERT INTO tenants (tenant_name, contact_person, contact_id, contact_phone) 
                        VALUES (?, ?, ?, ?)
                        """
                        cursor.execute(insert_sql, (tenant_name, contact_person, contact_id, contact_phone))
                    
                    success_count += 1
                    
                except Exception as e:
                    fail_count += 1
                    fail_records.append((index + 2, f"导入失败：{str(e)}"))
            
            # 提交事务
            if not cancel_flag.is_set():
                self.conn.commit()
            
            # 关闭进度对话框
            progress_dialog.close()
            
            # 更新导入历史记录
            import_history['end_time'] = datetime.datetime.now()
            import_history['success_count'] = success_count
            import_history['fail_count'] = fail_count
            
            if cancel_flag.is_set():
                import_history['status'] = '已取消'
                QMessageBox.information(self, "提示", "已取消导入")
                return
            else:
                import_history['status'] = '完成'
            
            # 保存导入历史记录
            self._saveImportHistory(import_history)
            
            # 显示导入结果
            result_info = f"导入完成！\n成功导入：{success_count} 条记录\n导入失败：{fail_count} 条记录"
            
            if fail_count > 0:
                # 准备错误数据下载
                error_df = pd.DataFrame(fail_records, columns=['行号', '失败原因'])
                
                # 询问用户是否下载错误数据和查看导入历史
                reply = QMessageBox.question(
                    self, "导入结果", 
                    f"{result_info}\n\n是否下载错误数据？",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No
                )
                
                if reply == QMessageBox.Yes:
                    # 保存错误数据到Excel
                    error_file_path, _ = QFileDialog.getSaveFileName(
                        self, "保存错误数据", "", "Excel Files (*.xlsx);;All Files (*)"
                    )
                    
                    if error_file_path:
                        try:
                            with pd.ExcelWriter(error_file_path, engine='openpyxl') as writer:
                                error_df.to_excel(writer, index=False, sheet_name='错误记录')
                                
                                # 设置列宽自适应
                                worksheet = writer.sheets['错误记录']
                                for column in worksheet.columns:
                                    max_length = 0
                                    column_letter = column[0].column_letter
                                    for cell in column:
                                        try:
                                            if len(str(cell.value)) > max_length:
                                                max_length = len(str(cell.value))
                                        except:
                                            pass
                                    adjusted_width = min(max_length + 2, 50)
                                    worksheet.column_dimensions[column_letter].width = adjusted_width
                            
                            QMessageBox.information(self, "成功", f"错误数据已保存到：{error_file_path}")
                        except Exception as e:
                            log_error(f"保存错误数据失败: {str(e)}")
                            QMessageBox.warning(self, "警告", f"保存错误数据失败：{str(e)}")
                
                # 询问是否查看导入历史
                history_reply = QMessageBox.question(
                    self, "导入历史",
                    "是否查看导入历史记录？",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No
                )
                
                if history_reply == QMessageBox.Yes:
                    self._showImportHistory()
            else:
                QMessageBox.information(self, "成功", result_info)
                
                # 询问是否查看导入历史
                history_reply = QMessageBox.question(
                    self, "导入历史",
                    "是否查看导入历史记录？",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No
                )
                
                if history_reply == QMessageBox.Yes:
                    self._showImportHistory()
            
            # 刷新承租人列表
            self.queryTenants()
            
        except pd.errors.EmptyDataError:
            progress_dialog.close()
            QMessageBox.warning(self, "错误", "Excel文件为空或格式不正确")
        except pd.errors.ParserError:
            progress_dialog.close()
            QMessageBox.warning(self, "错误", "无法解析Excel文件，请检查文件格式")
        except ImportError:
            progress_dialog.close()
            QMessageBox.critical(self, "错误", "缺少必要的库，请安装pandas和openpyxl库")
        except Exception as e:
            progress_dialog.close()
            log_error(f"导入Excel文件时发生错误: {str(e)}")
            QMessageBox.critical(self, "错误", f"导入过程中发生错误：{str(e)}")
    
    def _saveImportHistory(self, import_history):
        """保存导入历史记录"""
        # 导入历史记录将保存在内存中，实际应用中也可以保存到数据库或文件中
        if not hasattr(self, '_import_history_list'):
            self._import_history_list = []
        
        # 限制历史记录数量，只保留最近10条
        if len(self._import_history_list) >= 10:
            self._import_history_list.pop(0)
        
        self._import_history_list.append(import_history)
        log_info(f"保存导入历史记录: {import_history}")
    
    def _showImportHistory(self):
        """显示导入历史记录"""
        if not hasattr(self, '_import_history_list') or not self._import_history_list:
            QMessageBox.information(self, "导入历史", "暂无导入历史记录")
            return
        
        # 创建历史记录对话框
        history_dialog = QMessageBox(self)
        history_dialog.setWindowTitle("导入历史记录")
        history_dialog.setIcon(QMessageBox.Information)
        
        # 构建历史记录文本
        history_text = "最近导入历史：\n\n"
        for i, history in enumerate(reversed(self._import_history_list), 1):
            start_time = history['start_time'].strftime("%Y-%m-%d %H:%M:%S")
            end_time = history.get('end_time', '').strftime("%Y-%m-%d %H:%M:%S") if 'end_time' in history else 'N/A'
            file_name = history['file_name']
            status = history['status']
            success_count = history.get('success_count', 0)
            fail_count = history.get('fail_count', 0)
            
            history_text += f"{i}. 文件: {file_name}\n"
            history_text += f"   开始时间: {start_time}\n"
            history_text += f"   结束时间: {end_time}\n"
            history_text += f"   状态: {status}\n"
            history_text += f"   成功/失败: {success_count}/{fail_count}\n\n"
        
        history_dialog.setText(history_text)
        history_dialog.setStandardButtons(QMessageBox.Ok)
        history_dialog.exec_()
    
    def exportTenantToExcel(self):
        """导出承租人资料到Excel"""
        # 调用优化的Excel导出方法
        headers = ['承租人名称', '联系人姓名', '联系人身份证', '联系人电话']
        
        # 从表格获取数据
        data = []
        for row in range(self.tenant_table.rowCount()):
            row_data = []
            # 跳过ID列，从第1列开始获取数据
            for col in range(1, self.tenant_table.columnCount()):
                item = self.tenant_table.item(row, col)
                row_data.append(item.text() if item else '')
            data.append(row_data)
        
        # 选择保存文件路径
        file_path, _ = QFileDialog.getSaveFileName(
            self, "导出Excel", "", "Excel Files (*.xlsx);;All Files (*)"
        )
        
        if file_path:
            if self.optimizedExportToExcel(headers, data, file_path, "承租人资料"):
                QMessageBox.information(self, "成功", f"承租人资料已成功导出到\n{file_path}")
            else:
                QMessageBox.critical(self, "错误", "导出承租人资料失败")
    
    def optimizedExportToExcel(self, headers, data, file_path, sheet_name):
        """优化的Excel导出方法"""
        # 与HouseDataModule中的方法相同，可以考虑提取到基类中
        try:
            log_info(f"开始导出Excel文件: {file_path}, 工作表: {sheet_name}")
            
            # 导入必要的库
            import pandas as pd
            from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
            from openpyxl.utils import get_column_letter
            
            # 创建DataFrame
            df = pd.DataFrame(data, columns=headers)
            
            # 创建ExcelWriter对象并写入文件
            with pd.ExcelWriter(file_path, engine='openpyxl') as writer:
                df.to_excel(writer, index=False, sheet_name=sheet_name)
                
                # 获取工作表
                worksheet = writer.sheets[sheet_name]
                
                # 设置边框样式
                thin_border = Border(
                    left=Side(style='thin'),
                    right=Side(style='thin'),
                    top=Side(style='thin'),
                    bottom=Side(style='thin')
                )
                
                # 设置表头样式
                header_font = Font(bold=True, color="FFFFFF")
                header_fill = PatternFill(start_color="4F81BD", end_color="4F81BD", fill_type="solid")
                header_alignment = Alignment(horizontal="center", vertical="center")
                
                # 设置数据单元格样式
                data_alignment = Alignment(horizontal="center", vertical="center")
                
                # 应用样式并计算列宽
                column_widths = {}
                
                # 处理表头
                for col_idx, header in enumerate(headers, 1):
                    cell = worksheet.cell(row=1, column=col_idx)
                    cell.font = header_font
                    cell.fill = header_fill
                    cell.alignment = header_alignment
                    cell.border = thin_border
                    
                    # 计算表头列宽
                    column_widths[col_idx] = len(str(header)) + 2
                
                # 处理数据行
                for row_idx, row_data in enumerate(data, 2):
                    for col_idx, cell_value in enumerate(row_data, 1):
                        cell = worksheet.cell(row=row_idx, column=col_idx)
                        cell.alignment = data_alignment
                        cell.border = thin_border
                        
                        # 更新列宽
                        value_length = len(str(cell_value)) + 2
                        if value_length > column_widths.get(col_idx, 0):
                            column_widths[col_idx] = value_length
                
                # 设置自适应列宽
                for col_idx, width in column_widths.items():
                    worksheet.column_dimensions[get_column_letter(col_idx)].width = min(width, 50)
            
            log_info(f"Excel文件导出成功: {file_path}")
            return True
        except Exception as e:
            log_error(f"导出Excel文件时发生错误: {str(e)}")
            return False


class LandlordDataModule(QWidget):
    """出租人资料子页面模块"""
    
    def __init__(self):
        super().__init__()
        self.conn = None  # 数据库连接将在loadLandlords方法中设置
        self.initUI()
    
    def initUI(self):
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建出租人资料框架
        landlord_data_group = QGroupBox('出租人资料')
        landlord_layout = QVBoxLayout(landlord_data_group)
        
        # 创建出租人资料输入表单
        landlord_form_layout = QFormLayout()
        
        # 出租方（甲方）
        self.landlord_name_edit = QLineEdit()
        landlord_form_layout.addRow('出租方（甲方）:', self.landlord_name_edit)
        
        # 法定代表人
        self.legal_representative_edit = QLineEdit()
        landlord_form_layout.addRow('法定代表人:', self.legal_representative_edit)
        
        # 分管负责人
        self.person_in_charge_edit = QLineEdit()
        landlord_form_layout.addRow('分管负责人:', self.person_in_charge_edit)
        
        # 创建水平布局用于放置联系电话和默认字段
        contact_default_layout = QHBoxLayout()
        
        # 联系电话
        contact_phone_label = QLabel('联系电话:')
        self.landlord_contact_phone_edit = QLineEdit()
        contact_default_layout.addWidget(contact_phone_label)
        contact_default_layout.addWidget(self.landlord_contact_phone_edit)
        contact_default_layout.addStretch()
        
        # 默认（复选框）
        default_label = QLabel('默认:')
        self.landlord_is_default_checkbox = QCheckBox()
        contact_default_layout.addWidget(default_label)
        contact_default_layout.addWidget(self.landlord_is_default_checkbox)
        
        # 将水平布局添加到表单布局
        landlord_form_layout.addRow(contact_default_layout)
        
        # 添加表单到布局
        landlord_layout.addLayout(landlord_form_layout)
        
        # 创建按钮布局
        landlord_button_layout = QHBoxLayout()
        
        # 添加按钮
        self.add_landlord_button = QPushButton('添加')
        self.add_landlord_button.clicked.connect(self.addLandlord)
        landlord_button_layout.addWidget(self.add_landlord_button)
        
        # 编辑按钮
        self.edit_landlord_button = QPushButton('编辑')
        self.edit_landlord_button.clicked.connect(self.editLandlord)
        landlord_button_layout.addWidget(self.edit_landlord_button)
        
        # 删除按钮
        self.delete_landlord_button = QPushButton('删除')
        self.delete_landlord_button.clicked.connect(self.deleteLandlord)
        landlord_button_layout.addWidget(self.delete_landlord_button)
        
        # 查询按钮
        self.query_landlord_button = QPushButton('查询')
        self.query_landlord_button.clicked.connect(self.queryLandlords)
        landlord_button_layout.addWidget(self.query_landlord_button)
        
        # 重置按钮
        self.reset_landlord_button = QPushButton('重置')
        self.reset_landlord_button.clicked.connect(self.resetLandlordForm)
        landlord_button_layout.addWidget(self.reset_landlord_button)
        
        # 添加按钮布局到主布局
        landlord_layout.addLayout(landlord_button_layout)
        
        # 创建出租人资料表格
        self.landlord_table = QTableWidget()
        self.landlord_table.setColumnCount(6)
        self.landlord_table.setHorizontalHeaderLabels(['ID', '默认', '出租方（甲方）', '法定代表人', '分管负责人', '联系电话'])
        # 设置ID列不可见
        self.landlord_table.setColumnHidden(0, True)
        # 设置默认列宽
        self.landlord_table.setColumnWidth(1, 60)
        # 设置表格列宽自适应
        self.landlord_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # 为表格添加双击事件
        self.landlord_table.cellDoubleClicked.connect(self.onLandlordTableDoubleClick)
        
        # 添加表格到布局
        landlord_layout.addWidget(self.landlord_table)
        
        # 添加框架到主布局
        main_layout.addWidget(landlord_data_group)
    
    def loadLandlords(self, conn):
        # 设置数据库连接
        self.conn = conn
        # 加载所有出租人资料
        self.queryLandlords()
    
    def queryLandlords(self):
        """查询出租人资料"""
        if not self.conn:
            return
            
        try:
            # 获取查询条件
            landlord_name = self.landlord_name_edit.text().strip()
            legal_representative = self.legal_representative_edit.text().strip()
            person_in_charge = self.person_in_charge_edit.text().strip()
            contact_phone = self.landlord_contact_phone_edit.text().strip()
            is_default = self.landlord_is_default_checkbox.isChecked()
            
            # 构建查询SQL
            query_sql = "SELECT id, is_default, landlord_name, legal_representative, person_in_charge, contact_phone FROM landlords WHERE 1=1"
            params = []
            
            if landlord_name:
                query_sql += " AND landlord_name LIKE ?"
                params.append(f"%{landlord_name}%")
            
            if legal_representative:
                query_sql += " AND legal_representative LIKE ?"
                params.append(f"%{legal_representative}%")
            
            if person_in_charge:
                query_sql += " AND person_in_charge LIKE ?"
                params.append(f"%{person_in_charge}%")
            
            if contact_phone:
                query_sql += " AND contact_phone LIKE ?"
                params.append(f"%{contact_phone}%")
            
            if is_default:
                query_sql += " AND is_default = 1"
            
            query_sql += " ORDER BY is_default DESC, landlord_name"
            
            # 执行查询
            cursor = self.conn.cursor()
            cursor.execute(query_sql, params)
            landlords = cursor.fetchall()
            
            # 清空表格
            self.landlord_table.setRowCount(0)
            
            # 填充表格
            for row_data in landlords:
                row_position = self.landlord_table.rowCount()
                self.landlord_table.insertRow(row_position)
                
                for col_idx, value in enumerate(row_data):
                    if col_idx == 1:  # 默认列
                        item = QTableWidgetItem("√" if value else "")
                        item.setTextAlignment(Qt.AlignCenter | Qt.AlignVCenter)
                    else:
                        item = QTableWidgetItem(str(value) if value is not None else '')
                    
                    # 所有单元格不可编辑
                    item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                    self.landlord_table.setItem(row_position, col_idx, item)
        except Exception as e:
            log_error(f"查询出租人资料失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"查询出租人资料失败: {str(e)}")
    
    def addLandlord(self):
        """添加出租人资料"""
        self._saveLandlord(None)
    
    def editLandlord(self):
        """编辑出租人资料"""
        # 获取选中的行
        selected_rows = self.landlord_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "提示", "请先选择一行要编辑的数据")
            return
            
        # 获取选中行的ID
        row = selected_rows[0].row()
        landlord_id = self.landlord_table.item(row, 0).text()
        
        # 调用保存方法进行编辑
        self._saveLandlord(landlord_id)
    
    def _saveLandlord(self, landlord_id):
        """保存出租人资料（添加或编辑）"""
        if not self.conn:
            return
            
        try:
            # 获取表单数据
            landlord_name = self.landlord_name_edit.text().strip()
            legal_representative = self.legal_representative_edit.text().strip()
            person_in_charge = self.person_in_charge_edit.text().strip()
            contact_phone = self.landlord_contact_phone_edit.text().strip()
            is_default = self.landlord_is_default_checkbox.isChecked()
            
            # 验证必填字段
            if not landlord_name:
                QMessageBox.warning(self, "提示", "出租方（甲方）不能为空")
                return
            
            # 验证出租人名称唯一性（编辑时排除当前记录）
            cursor = self.conn.cursor()
            if landlord_id:
                cursor.execute("SELECT id FROM landlords WHERE landlord_name = ? AND id != ?", (landlord_name, landlord_id))
            else:
                cursor.execute("SELECT id FROM landlords WHERE landlord_name = ?", (landlord_name,))
                
            if cursor.fetchone():
                QMessageBox.warning(self, "提示", "出租方名称已存在，请使用其他名称")
                return
            
            # 开始事务
            cursor = self.conn.cursor()
            
            # 如果设置为默认，先将其他记录设为非默认
            if is_default:
                cursor.execute("UPDATE landlords SET is_default = 0")
            
            # 保存数据
            if landlord_id:
                # 编辑现有记录
                cursor.execute(
                    "UPDATE landlords SET landlord_name=?, legal_representative=?, person_in_charge=?, contact_phone=?, is_default=? WHERE id=?",
                    (landlord_name, legal_representative, person_in_charge, contact_phone, is_default, landlord_id)
                )
                log_info(f"编辑出租人资料: ID={landlord_id}")
                QMessageBox.information(self, "成功", "出租人资料编辑成功")
            else:
                # 添加新记录
                cursor.execute(
                    "INSERT INTO landlords (landlord_name, legal_representative, person_in_charge, contact_phone, is_default) VALUES (?, ?, ?, ?, ?)",
                    (landlord_name, legal_representative, person_in_charge, contact_phone, is_default)
                )
                log_info(f"添加出租人资料: 名称={landlord_name}")
                QMessageBox.information(self, "成功", "出租人资料添加成功")
                
            # 提交事务
            self.conn.commit()
            
            # 重置表单
            self.resetLandlordForm()
            
            # 重新加载数据
            self.queryLandlords()
        except Exception as e:
            log_error(f"保存出租人资料失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"保存出租人资料失败: {str(e)}")
            if self.conn:
                self.conn.rollback()
    
    def deleteLandlord(self):
        """删除出租人资料"""
        if not self.conn:
            return
            
        # 获取选中的行
        selected_rows = self.landlord_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "提示", "请先选择要删除的数据")
            return
            
        # 确认删除
        reply = QMessageBox.question(self, "确认删除", "确定要删除选中的出租人资料吗？", 
                                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply != QMessageBox.Yes:
            return
            
        try:
            # 开始事务
            cursor = self.conn.cursor()
            
            deleted_count = 0
            for row in selected_rows:
                landlord_id = self.landlord_table.item(row.row(), 0).text()
                
                # 删除记录
                cursor.execute("DELETE FROM landlords WHERE id=?", (landlord_id,))
                deleted_count += 1
            
            # 提交事务
            self.conn.commit()
            
            if deleted_count > 0:
                log_info(f"删除出租人资料: 共删除{deleted_count}条记录")
                QMessageBox.information(self, "成功", f"成功删除{deleted_count}条出租人资料")
                # 重新加载数据
                self.queryLandlords()
        except Exception as e:
            log_error(f"删除出租人资料失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"删除出租人资料失败: {str(e)}")
            if self.conn:
                self.conn.rollback()
    
    def resetLandlordForm(self):
        """重置出租人表单，清除数据并重新加载"""
        # 清除表单数据
        self.landlord_name_edit.clear()
        self.legal_representative_edit.clear()
        self.person_in_charge_edit.clear()
        self.landlord_contact_phone_edit.clear()
        self.landlord_is_default_checkbox.setChecked(False)
        
        # 重新加载数据，恢复到初始状态
        self.queryLandlords()
    
    def onLandlordTableDoubleClick(self, row, column):
        """处理表格双击事件，用于编辑数据"""
        # 将选中行的数据填充到表单中
        landlord_id = self.landlord_table.item(row, 0).text()
        self.landlord_name_edit.setText(self.landlord_table.item(row, 2).text())
        self.legal_representative_edit.setText(self.landlord_table.item(row, 3).text())
        self.person_in_charge_edit.setText(self.landlord_table.item(row, 4).text())
        self.landlord_contact_phone_edit.setText(self.landlord_table.item(row, 5).text())
        self.landlord_is_default_checkbox.setChecked(self.landlord_table.item(row, 1).text() == "√")


class UtilityFeeModule(QWidget):
    """水电费标准子页面模块"""
    
    def __init__(self):
        super().__init__()
        self.conn = None  # 数据库连接将在loadUtilityFees方法中设置
        self.initUI()
    
    def initUI(self):
        # 创建主布局
        main_layout = QVBoxLayout(self)
        
        # 创建水电费标准框架
        utility_fee_group = QGroupBox('水电费标准')
        utility_fee_layout = QVBoxLayout(utility_fee_group)
        
        # 创建水电费标准输入表单
        utility_fee_form_layout = QFormLayout()
        
        # 房屋类型
        self.utility_house_type_combo = QComboBox()
        self.utility_house_type_combo.setEditable(False)  # 设置为不可编辑状态，确保用户只能从预设选项中选择
        self.utility_house_type_combo.setInsertPolicy(QComboBox.NoInsert)  # 防止用户插入新项
        utility_fee_form_layout.addRow('房屋类型:', self.utility_house_type_combo)
        
        # 水费标准
        self.water_fee_edit = QLineEdit()
        utility_fee_form_layout.addRow('水费标准(元/吨):', self.water_fee_edit)
        
        # 电费标准
        self.electricity_fee_edit = QLineEdit()
        utility_fee_form_layout.addRow('电费标准(元/度):', self.electricity_fee_edit)
        
        # 添加表单到布局
        utility_fee_layout.addLayout(utility_fee_form_layout)
        
        # 创建按钮布局
        utility_fee_button_layout = QHBoxLayout()
        
        # 添加按钮
        self.add_utility_fee_button = QPushButton('添加')
        self.add_utility_fee_button.clicked.connect(self.addUtilityFee)
        utility_fee_button_layout.addWidget(self.add_utility_fee_button)
        
        # 编辑按钮
        self.edit_utility_fee_button = QPushButton('编辑')
        self.edit_utility_fee_button.clicked.connect(self.editUtilityFee)
        utility_fee_button_layout.addWidget(self.edit_utility_fee_button)
        
        # 删除按钮
        self.delete_utility_fee_button = QPushButton('删除')
        self.delete_utility_fee_button.clicked.connect(self.deleteUtilityFee)
        utility_fee_button_layout.addWidget(self.delete_utility_fee_button)
        
        # 查询按钮
        self.query_utility_fee_button = QPushButton('查询')
        self.query_utility_fee_button.clicked.connect(self.queryUtilityFees)
        utility_fee_button_layout.addWidget(self.query_utility_fee_button)
        
        # 重置按钮
        self.reset_utility_fee_button = QPushButton('重置')
        self.reset_utility_fee_button.clicked.connect(self.resetUtilityFeeForm)
        utility_fee_button_layout.addWidget(self.reset_utility_fee_button)
        
        # 添加按钮布局到主布局
        utility_fee_layout.addLayout(utility_fee_button_layout)
        
        # 创建水电费标准表格
        self.utility_fee_table = QTableWidget()
        self.utility_fee_table.setColumnCount(4)
        self.utility_fee_table.setHorizontalHeaderLabels(['ID', '房屋类型', '水费标准(元/吨)', '电费标准(元/度)'])
        # 设置ID列不可见
        self.utility_fee_table.setColumnHidden(0, True)
        # 设置表格列宽自适应
        self.utility_fee_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # 为表格添加双击事件
        self.utility_fee_table.cellDoubleClicked.connect(self.onUtilityFeeTableDoubleClick)
        
        # 添加表格到布局
        utility_fee_layout.addWidget(self.utility_fee_table)
        
        # 添加框架到主布局
        main_layout.addWidget(utility_fee_group)
    
    def loadUtilityFees(self, conn):
        # 设置数据库连接
        self.conn = conn
        # 加载所有不同的房屋类型到下拉列表
        self.loadHouseTypes()
        # 加载所有水电费标准
        self.queryUtilityFees()
    
    def loadHouseTypes(self):
        """从数据库中加载所有不同的房屋类型到下拉列表中"""
        if not self.conn:
            return
            
        try:
            # 保存当前选中的房屋类型
            current_utility_type = self.utility_house_type_combo.currentText()
            
            # 清空水电费标准模块的下拉列表
            self.utility_house_type_combo.clear()
            
            # 确保下拉列表为只读状态
            self.utility_house_type_combo.setEditable(False)
            self.utility_house_type_combo.setInsertPolicy(QComboBox.NoInsert)
            
            # 首先添加'全部'选项
            self.utility_house_type_combo.addItem('全部')
            
            # 从数据库中获取所有不同的房屋类型
            cursor = self.conn.cursor()
            cursor.execute("SELECT DISTINCT house_type FROM houses WHERE house_type IS NOT NULL AND house_type != '' ORDER BY house_type")
            
            # 添加从数据库获取的房屋类型
            db_house_types = []
            for row in cursor.fetchall():
                house_type = row[0]
                if house_type and house_type != '全部':
                    self.utility_house_type_combo.addItem(house_type)
                    db_house_types.append(house_type)
            
            # 如果数据库中没有房屋类型，添加一些默认选项作为后备
            if len(db_house_types) == 0:
                default_types = ['门面', '办公室', '仓库', '招待所', '其它']
                for default_type in default_types:
                    self.utility_house_type_combo.addItem(default_type)
            
            # 尝试恢复之前选中的房屋类型
            if current_utility_type:
                index = self.utility_house_type_combo.findText(current_utility_type)
                if index != -1:
                    self.utility_house_type_combo.setCurrentIndex(index)
                else:
                    # 如果找不到之前的类型，默认选择'全部'
                    self.utility_house_type_combo.setCurrentIndex(0)
            else:
                # 如果之前没有选中的值，默认选择'全部'
                self.utility_house_type_combo.setCurrentIndex(0)
        except Exception as e:
            log_error(f"加载房屋类型失败: {str(e)}")
            # 发生错误时，至少添加默认选项
            self.utility_house_type_combo.clear()
            self.utility_house_type_combo.setEditable(False)
            self.utility_house_type_combo.setInsertPolicy(QComboBox.NoInsert)
            self.utility_house_type_combo.addItems(['全部', '门面', '办公室', '仓库', '招待所', '其它'])
    
    def queryUtilityFees(self):
        """查询水电费标准"""
        # 确保数据库连接有效
        if not self.conn:
            QMessageBox.critical(self, "错误", "查询水电费标准失败: 数据库连接为空")
            return
            
        try:
            # 获取查询条件
            house_type = self.utility_house_type_combo.currentText().strip()
            
            # 构建查询SQL，支持根据房屋类型进行过滤
            query_sql = "SELECT id, house_type, water_fee, electricity_fee FROM utility_fee"
            params = []
            
            # 如果选择了有效的房屋类型，则添加过滤条件
            if house_type and house_type != '全部':
                query_sql += " WHERE house_type = ?"
                params.append(house_type)
            
            query_sql += " ORDER BY house_type"
            
            # 执行查询
            cursor = self.conn.cursor()
            cursor.execute(query_sql, params)
            utility_fees = cursor.fetchall()
            
            # 确保表格有足够的列
            if self.utility_fee_table.columnCount() != 4:
                self.utility_fee_table.setColumnCount(4)
                self.utility_fee_table.setHorizontalHeaderLabels(['ID', '房屋类型', '水费(元/吨)', '电费(元/度)'])
            
            # 清空表格并重新填充
            self.utility_fee_table.setRowCount(0)
            
            if not utility_fees:
                # 注释掉提示框，避免在页面加载时显示
                # QMessageBox.information(self, "提示", "未查询到符合条件的水电费标准记录")
                return
            
            # 填充表格数据
            for row_idx, row_data in enumerate(utility_fees):
                self.utility_fee_table.insertRow(row_idx)
                
                # 正确处理sqlite3.Row对象和tuple对象
                id_value = None
                type_value = None
                water_value = 0.0
                electricity_value = 0.0
                
                # 处理sqlite3.Row对象
                if hasattr(row_data, 'keys'):
                    id_value = row_data['id']
                    type_value = row_data['house_type']
                    water_value = row_data['water_fee'] if row_data['water_fee'] is not None else 0.0
                    electricity_value = row_data['electricity_fee'] if row_data['electricity_fee'] is not None else 0.0
                # 处理tuple对象
                elif isinstance(row_data, tuple) and len(row_data) >= 4:
                    id_value = row_data[0]
                    type_value = row_data[1]
                    water_value = row_data[2] if row_data[2] is not None else 0.0
                    electricity_value = row_data[3] if row_data[3] is not None else 0.0
                else:
                    continue
                
                # 填充ID列
                id_item = QTableWidgetItem(str(id_value))
                id_item.setFlags(id_item.flags() & ~Qt.ItemIsEditable)
                self.utility_fee_table.setItem(row_idx, 0, id_item)
                
                # 填充房屋类型列
                type_item = QTableWidgetItem(str(type_value) if type_value is not None else '')
                type_item.setFlags(type_item.flags() & ~Qt.ItemIsEditable)
                self.utility_fee_table.setItem(row_idx, 1, type_item)
                
                # 填充水费列
                water_item = QTableWidgetItem(f"{water_value:.2f}")
                water_item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                water_item.setFlags(water_item.flags() & ~Qt.ItemIsEditable)
                self.utility_fee_table.setItem(row_idx, 2, water_item)
                
                # 填充电费列
                electricity_item = QTableWidgetItem(f"{electricity_value:.2f}")
                electricity_item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                electricity_item.setFlags(electricity_item.flags() & ~Qt.ItemIsEditable)
                self.utility_fee_table.setItem(row_idx, 3, electricity_item)
            
            # 调整列宽并刷新表格
            self.utility_fee_table.resizeColumnsToContents()
            self.utility_fee_table.viewport().update()
            log_info("水电费标准表格数据更新完成")
            
        except Exception as e:
            error_msg = f"查询水电费标准失败: {str(e)}"
            log_error(error_msg)
            import traceback
            log_error(f"异常详情: {traceback.format_exc()}")
            QMessageBox.critical(self, "错误", error_msg)
    
    def addUtilityFee(self):
        """添加水电费标准"""
        self._saveUtilityFee(None)
    
    def editUtilityFee(self):
        """编辑水电费标准"""
        # 获取选中的行
        selected_rows = self.utility_fee_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "提示", "请先选择一行要编辑的数据")
            return
            
        # 获取选中行的ID和房屋类型
        row = selected_rows[0].row()
        utility_fee_id = self.utility_fee_table.item(row, 0).text()
        house_type = self.utility_fee_table.item(row, 1).text()
        water_fee = self.utility_fee_table.item(row, 2).text()
        electricity_fee = self.utility_fee_table.item(row, 3).text()
        
        # 将选中记录的数据填充到表单中
        # 确保房屋类型下拉框为只读状态
        self.utility_house_type_combo.setEditable(False)
        self.utility_house_type_combo.setInsertPolicy(QComboBox.NoInsert)
        
        # 确保房屋类型下拉框中包含该房屋类型
        if self.utility_house_type_combo.findText(house_type) == -1:
            # 如果下拉框中没有该房屋类型，先刷新下拉框数据
            self.loadHouseTypes()
            # 如果仍然没有，手动添加（仅用于显示）
            if self.utility_house_type_combo.findText(house_type) == -1:
                self.utility_house_type_combo.addItem(house_type)
        
        # 设置选中的房屋类型（保持只读）
        self.utility_house_type_combo.setCurrentText(house_type)
        # 设置水费和电费
        self.water_fee_edit.setText(water_fee)
        self.electricity_fee_edit.setText(electricity_fee)
        
        # 调用保存方法进行编辑
        self._saveUtilityFee(utility_fee_id)
    
    def _saveUtilityFee(self, utility_fee_id):
        """保存水电费标准（添加或编辑）"""
        if not self.conn:
            return
            
        try:
            # 获取表单数据
            house_type = self.utility_house_type_combo.currentText().strip()
            water_fee_text = self.water_fee_edit.text().strip()
            electricity_fee_text = self.electricity_fee_edit.text().strip()
            
            # 验证必填字段
            if not house_type:
                QMessageBox.warning(self, "提示", "房屋类型不能为空")
                return
            
            # 验证不能选择'全部'作为房屋类型
            if house_type == '全部':
                QMessageBox.warning(self, "提示", "不能选择'全部'作为房屋类型")
                return
            
            # 验证数字格式
            try:
                water_fee = float(water_fee_text) if water_fee_text else 0
                electricity_fee = float(electricity_fee_text) if electricity_fee_text else 0
                
                if water_fee < 0 or electricity_fee < 0:
                    QMessageBox.warning(self, "提示", "水费和电费标准不能为负数")
                    return
            except ValueError:
                QMessageBox.warning(self, "提示", "水费和电费标准必须是数字")
                return
            
            # 验证房屋类型唯一性（编辑时排除当前记录）
            cursor = self.conn.cursor()
            if utility_fee_id:
                cursor.execute("SELECT id FROM utility_fee WHERE house_type = ? AND id != ?", (house_type, utility_fee_id))
            else:
                cursor.execute("SELECT id FROM utility_fee WHERE house_type = ?", (house_type,))
                
            if cursor.fetchone():
                QMessageBox.warning(self, "提示", f"{house_type}的水电费标准已存在，请使用其他房屋类型")
                return
            
            # 保存数据
            if utility_fee_id:
                # 编辑现有记录 - 只更新水费和电费，保持房屋类型不变
                # 从表格中获取原始房屋类型，确保不被修改
                selected_rows = self.utility_fee_table.selectionModel().selectedRows()
                if selected_rows:
                    row = selected_rows[0].row()
                    original_house_type = self.utility_fee_table.item(row, 1).text()
                    house_type = original_house_type
                
                cursor.execute(
                    "UPDATE utility_fee SET water_fee=?, electricity_fee=? WHERE id=?",
                    (water_fee, electricity_fee, utility_fee_id)
                )
                log_info(f"编辑水电费标准: ID={utility_fee_id}, 房屋类型={house_type}")
                QMessageBox.information(self, "成功", "水电费标准编辑成功")
            else:
                # 添加新记录
                cursor.execute(
                    "INSERT INTO utility_fee (house_type, water_fee, electricity_fee) VALUES (?, ?, ?)",
                    (house_type, water_fee, electricity_fee)
                )
                log_info(f"添加水电费标准: 房屋类型={house_type}")
                QMessageBox.information(self, "成功", "水电费标准添加成功")
                
            # 提交事务
            self.conn.commit()
            
            # 重置表单
            self.resetUtilityFeeForm()
            
            # 重新加载数据
            self.queryUtilityFees()
        except Exception as e:
            log_error(f"保存水电费标准失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"保存水电费标准失败: {str(e)}")
            if self.conn:
                self.conn.rollback()
    
    def deleteUtilityFee(self):
        """删除水电费标准"""
        if not self.conn:
            return
            
        # 获取选中的行
        selected_rows = self.utility_fee_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "提示", "请先选择要删除的数据")
            return
            
        # 确认删除
        reply = QMessageBox.question(self, "确认删除", "确定要删除选中的水电费标准吗？", 
                                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply != QMessageBox.Yes:
            return
            
        try:
            # 开始事务
            cursor = self.conn.cursor()
            
            # 删除选中的记录
            for row in selected_rows:
                utility_fee_id = self.utility_fee_table.item(row.row(), 0).text()
                cursor.execute("DELETE FROM utility_fee WHERE id=?", (utility_fee_id,))
            
            # 提交事务
            self.conn.commit()
            
            log_info(f"删除水电费标准: 共删除{len(selected_rows)}条记录")
            QMessageBox.information(self, "成功", f"成功删除{len(selected_rows)}条水电费标准")
            
            # 重新加载数据
            self.queryUtilityFees()
        except Exception as e:
            log_error(f"删除水电费标准失败: {str(e)}")
            QMessageBox.critical(self, "错误", f"删除水电费标准失败: {str(e)}")
            if self.conn:
                self.conn.rollback()
    
    def resetUtilityFeeForm(self):
        """重置水电费标准表单，清除数据并重新加载"""
        # 清除表单数据
        self.utility_house_type_combo.setCurrentIndex(0)  # 重置为'全部'
        self.water_fee_edit.clear()
        self.electricity_fee_edit.clear()
        
        # 重新加载数据，恢复到初始状态
        self.queryUtilityFees()
        
        # 添加用户反馈，提示重置操作已完成
        log_info("水电费标准表单已重置")
    
    def onUtilityFeeTableDoubleClick(self, row, column):
        """处理表格双击事件，用于编辑数据"""
        # 将选中行的数据填充到表单中
        utility_fee_id = self.utility_fee_table.item(row, 0).text()
        
        # 设置房屋类型
        house_type = self.utility_fee_table.item(row, 1).text()
        index = self.utility_house_type_combo.findText(house_type)
        if index != -1:
            self.utility_house_type_combo.setCurrentIndex(index)
        
        # 设置水费标准
        water_fee_item = self.utility_fee_table.item(row, 2)
        if water_fee_item:
            # 移除可能的小数点后多余的零
            water_fee_text = water_fee_item.text().rstrip('0').rstrip('.') if '.' in water_fee_item.text() else water_fee_item.text()
            self.water_fee_edit.setText(water_fee_text)
        else:
            self.water_fee_edit.clear()
            
        # 设置电费标准
        electricity_fee_item = self.utility_fee_table.item(row, 3)
        if electricity_fee_item:
            # 移除可能的小数点后多余的零
            electricity_fee_text = electricity_fee_item.text().rstrip('0').rstrip('.') if '.' in electricity_fee_item.text() else electricity_fee_item.text()
            self.electricity_fee_edit.setText(electricity_fee_text)
        else:
            self.electricity_fee_edit.clear()